/*
 * File     : X86_CDecl_Unix.s
 * Created  : 28 Apr 2011
 *
 * Copyright © 2011 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

.intel_syntax
.text


////////////////////////////////////////////////////////////////////////////////
// Call for 1 argument                                                        //
////////////////////////////////////////////////////////////////////////////////

.globl dni_x86_cdecl_unix_call_1
    .type dni_x86_cdecl_unix_call_1, @function

dni_x86_cdecl_unix_call_1:
    // Java JNI signature is:
    //   int       fnptr
    //   <..>      arg0
    //
    // Stack:
    //            0    return address
    //            4    JNIEnv*
    //            8    jclass
    //           12    function pointer
    //           16    arg0

    // copy the displaced arguments
    mov       %ecx, [ %esp + 16 ]
    mov       [ %esp +  4 ], %ecx

    // call the function
    jmp       [ %esp + 12 ]


////////////////////////////////////////////////////////////////////////////////
// Call for 2 arguments                                                       //
////////////////////////////////////////////////////////////////////////////////

.globl dni_x86_cdecl_unix_call_2
    .type dni_x86_cdecl_unix_call_2, @function

dni_x86_cdecl_unix_call_2:
    // Java JNI signature is:
    //   int       fnptr
    //   <..>      arg0
    //   <..>      arg1
    //
    // Stack:
    //            0    return address
    //            4    JNIEnv*
    //            8    jclass
    //           12    function pointer
    //           16    arg0
    //           20    arg1

    // copy the displaced arguments
    mov       %ecx, [ %esp + 16 ]
    mov       %edx, [ %esp + 20 ]
    mov       [ %esp +  4 ], %ecx
    mov       [ %esp +  8 ], %edx

    // call the function
    jmp       [ %esp + 12 ]


////////////////////////////////////////////////////////////////////////////////
// Call for 3 arguments                                                       //
////////////////////////////////////////////////////////////////////////////////

.globl dni_x86_cdecl_unix_call_3
    .type dni_x86_cdecl_unix_call_3, @function

dni_x86_cdecl_unix_call_3:
    // Java JNI signature is:
    //   int       fnptr
    //   <..>      arg0
    //   <..>      arg1
    //   <..>      arg2
    //
    // Stack:
    //            0    return address
    //            4    JNIEnv*
    //            8    jclass
    //           12    function pointer
    //           16    arg0
    //           20    arg1
    //           24    arg2

    // preserve function pointer
    mov       %eax, [ %esp + 12 ]

    // copy the displaced arguments
    mov       %ecx, [ %esp + 16 ]
    mov       %edx, [ %esp + 20 ]
    mov       [ %esp +  4 ], %ecx
    mov       [ %esp +  8 ], %edx
    mov       %ecx, [ %esp + 24 ]
    mov       [ %esp + 12 ], %ecx

    // call the function
    jmp       %eax


////////////////////////////////////////////////////////////////////////////////
// Call for 4 arguments                                                       //
////////////////////////////////////////////////////////////////////////////////

.globl dni_x86_cdecl_unix_call_4
    .type dni_x86_cdecl_unix_call_4, @function

dni_x86_cdecl_unix_call_4:
    // Java JNI signature is:
    //   int       fnptr
    //   <..>      arg0
    //   <..>      arg1
    //   <..>      arg2
    //   <..>      arg3
    //
    // Stack:
    //            0    return address
    //            4    JNIEnv*
    //            8    jclass
    //           12    function pointer
    //           16    arg0
    //           20    arg1
    //           24    arg2
    //           28    arg3

    // preserve function pointer
    mov       %eax, [ %esp + 12 ]

    // copy the displaced arguments
    mov       %ecx, [ %esp + 16 ]
    mov       %edx, [ %esp + 20 ]
    mov       [ %esp +  4 ], %ecx
    mov       [ %esp +  8 ], %edx
    mov       %ecx, [ %esp + 24 ]
    mov       %edx, [ %esp + 28 ]
    mov       [ %esp + 12 ], %ecx
    mov       [ %esp + 16 ], %edx

    // call the function
    jmp       %eax


////////////////////////////////////////////////////////////////////////////////
// Call for >= 4 arguments with no splitting of long / double                 //
////////////////////////////////////////////////////////////////////////////////

.globl dni_x86_cdecl_unix_call_displace_4
    .type dni_x86_cdecl_unix_call_displace_4, @function

dni_x86_cdecl_unix_call_displace_4:
    // Java JNI signature is:
    //   int       offset
    //   int       fnptr
    //   <..>      arg[4..]
    //   <..>      arg0
    //   <..>      arg1
    //   <..>      arg2
    //   <..>      arg3
    //
    // Stack:
    //            0    return address
    //            4    JNIEnv*
    //            8    jclass
    //           12    function pointer
    //           16    offset
    //           20    arg4 (or fragments thereof...)
    //           24    ...
    //   offset + 0    arg0
    //   offset + 4    arg1
    //   offset + 8    arg2
    //   offset +12    arg3

    // get offset and hence pointer to displaced arguments
    mov       %eax, [ %esp + 16 ]
    add       %eax, %esp

    // --> now %eax points to displaced arguments

    // copy the displaced arguments part #1
    mov       %ecx, [ %eax +  0 ]

    // interlude: preserve the function pointer
    mov       %edx, [ %esp + 12 ]
    mov       [ %eax ], %edx

    // copy the displaced arguments part #2
    mov       %edx, [ %eax +  4 ]
    mov       [ %esp +  4 ], %ecx
    mov       [ %esp +  8 ], %edx
    mov       %ecx, [ %eax +  8 ]
    mov       %edx, [ %eax + 12 ]
    mov       [ %esp + 12 ], %ecx
    mov       [ %esp + 16 ], %edx

    // call the function
    jmp       [ %eax ]


////////////////////////////////////////////////////////////////////////////////
// Call for >= 5 arguments with splitting of long / double                    //
////////////////////////////////////////////////////////////////////////////////


.globl dni_x86_cdecl_unix_call_displace_5
    .type dni_x86_cdecl_unix_call_displace_5, @function

dni_x86_cdecl_unix_call_displace_5:
    // Java JNI signature is:
    //   int       offset
    //   int       fnptr
    //   int       padding
    //   <..>      arg[5..]
    //   <..>      arg0
    //   <..>      arg1
    //   <..>      arg2
    //   <..>      arg3
    //   <..>      arg4
    //
    // Stack:
    //            0    return address
    //            4    JNIEnv*
    //            8    jclass
    //           12    function pointer
    //           16    offset
    //           20    padding
    //           24    arg5 (or fragments thereof...)
    //           28    ...
    //   offset + 0    arg0
    //   offset + 4    arg1
    //   offset + 8    arg2
    //   offset +12    arg3
    //   offset +16    arg4

    // get offset and hence pointer to displaced arguments
    mov       %eax, [ %esp + 16 ]
    add       %eax, %esp

    // --> now %eax points to displaced arguments

    // copy the displaced arguments part #1
    mov       %ecx, [ %eax +  0 ]

    // interlude: preserve the function pointer
    mov       %edx, [ %esp + 12 ]
    mov       [ %eax ], %edx

    // copy the displaced arguments part #2
    mov       %edx, [ %eax +  4 ]
    mov       [ %esp +  4 ], %ecx
    mov       [ %esp +  8 ], %edx
    mov       %ecx, [ %eax +  8 ]
    mov       %edx, [ %eax + 12 ]
    mov       [ %esp + 12 ], %ecx
    mov       [ %esp + 16 ], %edx
    mov       %ecx, [ %eax + 16 ]
    mov       [ %esp + 20 ], %ecx

    // call the function
    jmp       [ %eax ]


////////////////////////////////////////////////////////////////////////////////
// Call for 'n' arguments                                                     //
////////////////////////////////////////////////////////////////////////////////

// n >= 128, or variable arity

.globl dni_x86_cdecl_unix_call_n
    .type dni_x86_cdecl_unix_call_n, @function

dni_x86_cdecl_unix_call_n:
    // Java JNI signature is:
    //   int       fnptr
    //   int       argptr
    //   int       argcount
    //
    // Stack:
    //            0    return address
    //            4    JNIEnv*
    //            8    jclass
    //           12    function pointer
    //           16    argument pointer
    //           20    argument count (in units of 4-byte words)

    // prologue
    push      %ebp
    mov       %ebp, %esp
    push      %esi
    push      %edi

    // get argument pointer & count
    mov       %esi, [ %ebp + 4 + 16 ]
    mov       %ecx, [ %ebp + 4 + 20 ]

    // allocate stack for call
    lea       %edi, [ 0 + 4 * %ecx ]
	sub       %esp, %edi

    // copy the arguments
    mov       %edi, %esp
    rep movsd

    // call the function
    call      [ %ebp + 4 + 12 ]

    // clean the stack
    mov       %ecx, [ %ebp + 4 + 20 ]
    lea       %esp, [ %esp + 4 * %ecx ]

    // epilogue
    pop       %edi
    pop       %esi
    mov       %esp, %ebp
    pop       %ebp

    ret
